package com.cloudree.gllib.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.support.annotation.DrawableRes;
import android.support.annotation.RawRes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * Created by Administrator on 2017/10/17 0017.
 */
public class GLHelper {

    /**
     * load texture  mapping
     */
    public static int loadTexture(Context context, @DrawableRes int resId) {
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        int[] texture = new int[1];
        GLES20.glGenTextures(1, texture, 0);
        if (texture[0] != 0) {
            //loading resource
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled = false;
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId, options);

            if (bitmap == null) {
                throw new RuntimeException(resId + "can`t be decoded into a texture");
            }

            //bind bitmap
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

            GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

            bitmap.recycle();

        } else {
            throw new RuntimeException("Error load texture");
        }

        return texture[0];
    }

    /**
     * load textures
     */
    public static int[] loadTextures(Context context, @DrawableRes int[] resId) {
        if (resId == null || resId.length < 1) {
            throw new RuntimeException("Error resId is invalid");
        }

        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        int[] texture = new int[resId.length];
        GLES20.glGenTextures(resId.length, texture, 0);
        for (int i = 0; i < resId.length; i++) {
            if (texture[i] != 0) {
                //loading resource
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inScaled = false;
                Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId[i], options);

                if (bitmap == null) {
                    throw new RuntimeException(resId + "can`t be decoded into a texture");
                }

                //bind bitmap
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[i]);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
                GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

                GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

                bitmap.recycle();

            } else {
                throw new RuntimeException("Error load texture:index=" + i);
            }
        }
        return texture;
    }

    /**
     * generate shader
     * GLES20.GL_FRAGMENT_SHADER
     * GLES20.GL_VERTEX_SHADER
     */
    public static int generateShader(int shaderType, String shaderCode) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            final int[] compileStatus = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

            //if compile failed then delete it
            if (compileStatus[0] == 0) {
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        if (shader == 0) {
            throw new RuntimeException("Error create gl shader.");
        }
        return shader;
    }

    /**
     * generate gl program
     */
    public static int generateGlProgram(int vertexShader, int fragmentShader, String... attrs) {
        int program = GLES20.glCreateProgram();
        if (program != 0) {
            //attach shader
            GLES20.glAttachShader(program, vertexShader);
            GLES20.glAttachShader(program, fragmentShader);
            //bind attributes
            for (int i = 0; i < attrs.length; i++) {
                GLES20.glBindAttribLocation(program, i, attrs[i]);
            }

            //get link status
            final int[] linkStatus = new int[1];
            GLES20.glLinkProgram(program);
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            //check status
            if (linkStatus[0] == 0) {
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        if (program == 0) {
            throw new RuntimeException("Error create program");
        }
        return program;
    }

    /**
     * read raw files
     */
    public static String readRawFile(Context context, @RawRes int resId) {
        InputStream is = context.getResources().openRawResource(resId);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String str = "";
        StringBuffer sb = new StringBuffer();
        try {
            while ((str = br.readLine()) != null) {
                sb.append(str);
                sb.append("\n");
            }

        } catch (IOException e) {
            return null;
        }
        return sb.toString();
    }
}
